﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using MapleLib.WzLib;
using MapleLib.WzLib.Util;
using MapleLib.WzLib.WzProperties;

namespace MapleLib.Examples.MapEditor {
    public class WzMap {

        public int id;
        public string imgName;
        public WzImage img;
        public WzFile mapWZ;
        public WzFile npcWZ;
        public WzFile mobWZ;
        public WzFile reactorWZ;

        public int w = 0;
        public int h = 0;
        public int cX = 0;
        public int cY = 0;

        public int drawMask = 0;

        Hashtable mapInfo = new Hashtable();
        public List<WzBackgroundObject> mapBack = new List<WzBackgroundObject>();
        public List<WzLifeObject> mapLife = new List<WzLifeObject>();
        public List<List<WzLayerObject>> mapLayerTile = new List<List<WzLayerObject>>();
        public List<List<WzLayerObject>> mapLayerObj = new List<List<WzLayerObject>>();
        public List<WzReactorObject> mapReactor = new List<WzReactorObject>();
        public List<WzPortalObject> mapPortal = new List<WzPortalObject>();
        public List<WzLadderRopeObject> mapLadderRope = new List<WzLadderRopeObject>();
        public List<WzFootholdTreeObject> mapFootholdTree = new List<WzFootholdTreeObject>();
        public List<WzFootholdObject> mapFoothold = new List<WzFootholdObject>();
        //ToolTip

        public void load() {

            if (img["miniMap"] != null) {
                IWzImageProperty data = img["miniMap"];
                w = WzDataTool.getIntValue(data["width"]);
                h = WzDataTool.getIntValue(data["height"]);
                cX = WzDataTool.getIntValue(data["centerX"]);
                cY = WzDataTool.getIntValue(data["centerY"]);
                } else {
                IWzImageProperty data = img["info"];
                int left = WzDataTool.getIntValue(data["VRLeft"], 0);
                int top = WzDataTool.getIntValue(data["VRTop"], 0);
                int right = WzDataTool.getIntValue(data["VRRight"], 0);
                int bottom = WzDataTool.getIntValue(data["VRBottom"], 0);
                w = right - left;
                h = bottom - top;
                cX = -1 * left;
                cY = -1 * top;
                }

            if (w == 0 || h == 0) {
                w = 1000;
                h = 1000;
                cX = 500;
                cY = 500;
                //throw new Exception("Cannot Render Map: Illegal Dimensions");
                }

            for (int i = 0; i < 8; i++) {
                List<WzLayerObject> mapLayerTiles = new List<WzLayerObject>();
                List<WzLayerObject> mapLayerObjs = new List<WzLayerObject>();

                WzSubProperty layerData = (WzSubProperty)img[i.ToString()];
                WzSubProperty layerInfoData = (WzSubProperty)layerData["info"];
                WzSubProperty layerTileData = (WzSubProperty)layerData["tile"];
                WzSubProperty layerObjData = (WzSubProperty)layerData["obj"];
                string tileSet = null;

                if (layerInfoData != null && layerInfoData.WzProperties.Length > 0) {
                    tileSet = WzDataTool.getStringValue(layerInfoData["tS"]);
                    }

                foreach (WzSubProperty tileData in layerTileData.WzProperties) {
                    WzLayerObject layerObject = new WzLayerObject();
                    string tileSubset = WzDataTool.getStringValue(tileData["u"]);
                    int tileNumber = WzDataTool.getIntValue(tileData["no"]);
                    WzImage tileImg = mapWZ.WzDirectory.GetDirectoryByName("Tile").GetImageByName(tileSet + ".img");
                    WzCanvasProperty tileImageData = (WzCanvasProperty)tileImg[tileSubset][tileNumber.ToString()];
                    Bitmap image = tileImageData.PngProperty.PNG;
                    Point pos = new Point(WzDataTool.getIntValue(tileData["x"]), WzDataTool.getIntValue(tileData["y"]));
                    WzVectorProperty originVec = (WzVectorProperty)tileImageData["origin"];
                    int imageZ = WzDataTool.getIntValue(tileImageData["z"]);
                    Point origin = new Point(originVec.X.Value, originVec.Y.Value);
                    int zM = WzDataTool.getIntValue(tileImageData["zM"]);

                    layerObject.type = "t";
                    layerObject.flip = false;
                    layerObject.number = tileNumber;
                    layerObject.tileSet = tileSet;
                    layerObject.tileSubset = tileSubset;
                    layerObject.pos = pos;
                    layerObject.zM = zM;
                    layerObject.compareZ = zM + imageZ;
                    layerObject.image = image;
                    layerObject.origin = origin;
                    layerObject.map = this;

                    mapLayerTiles.Add(layerObject);
                    }

                foreach (WzSubProperty objData in layerObjData.WzProperties) {
                    WzLayerObject layerObject = new WzLayerObject();
                    string objectSet = WzDataTool.getStringValue(objData["oS"]);
                    string l0 = WzDataTool.getStringValue(objData["l0"]);
                    string l1 = WzDataTool.getStringValue(objData["l1"]);
                    string l2 = WzDataTool.getStringValue(objData["l2"]);
                    WzImage objImg = mapWZ.WzDirectory.GetDirectoryByName("Obj").GetImageByName(objectSet + ".img");
                    WzCanvasProperty objImageData = (WzCanvasProperty)objImg[l0][l1][l2]["0"];
                    Point pos = new Point(WzDataTool.getIntValue(objData["x"]), WzDataTool.getIntValue(objData["y"]));
                    WzVectorProperty originVec = (WzVectorProperty)objImageData["origin"];
                    int imageZ = WzDataTool.getIntValue(objImageData["z"]);
                    Bitmap image = objImageData.PngProperty.PNG;
                    Point origin = new Point(originVec.X.Value, originVec.Y.Value);
                    int z = WzDataTool.getIntValue(objData["z"]);
                    int zM = WzDataTool.getIntValue(objData["zM"]);
                    bool flip = WzDataTool.getIntValue(objData["f"]) > 0;

                    layerObject.type = "o";
                    layerObject.flip = flip;
                    layerObject.l0 = l0;
                    layerObject.l1 = l1;
                    layerObject.l2 = l2;
                    layerObject.objectSet = objectSet;
                    layerObject.pos = pos;
                    layerObject.z = z;
                    layerObject.zM = zM;
                    layerObject.compareZ = z + imageZ;
                    layerObject.image = image;
                    layerObject.origin = origin;
                    layerObject.map = this;

                    mapLayerObjs.Add(layerObject);
                    }

                mapLayerTiles.Sort(delegate(WzLayerObject o1, WzLayerObject o2) { return o1.compareZ.CompareTo(o2.compareZ); });
                mapLayerObjs.Sort(delegate(WzLayerObject o1, WzLayerObject o2) { return o1.compareZ.CompareTo(o2.compareZ); });

                mapLayerTile.Add(mapLayerTiles);
                mapLayerObj.Add(mapLayerObjs);
                }

            if (img["foothold"] != null) {
                WzSubProperty dataRoot = (WzSubProperty)img["foothold"];
                foreach (IWzImageProperty dataRoot1 in dataRoot.WzProperties) {
                    foreach (IWzImageProperty dataRoot2 in dataRoot1.WzProperties) {
                        foreach (IWzImageProperty dataRoot3 in dataRoot2.WzProperties) {
                            WzFootholdObject foothold = new WzFootholdObject();
                            foothold.LT = new Point(WzDataTool.getIntValue(dataRoot3["x1"]), WzDataTool.getIntValue(dataRoot3["y1"]));
                            foothold.RB = new Point(WzDataTool.getIntValue(dataRoot3["x2"]), WzDataTool.getIntValue(dataRoot3["y2"]));
                            foothold.map = this;
                            mapFoothold.Add(foothold);
                            }
                        }
                    }
                }

            if (img["reactor"] != null) {
                WzSubProperty dataRoot = (WzSubProperty)img["reactor"];
                foreach (IWzImageProperty data in dataRoot.WzProperties) {
                    WzReactorObject reactorObject = new WzReactorObject();

                    string idStr = WzDataTool.getStringValue(data["id"]);
                    string imgName = idStr + ".img";
                    Point pos = new Point(WzDataTool.getIntValue(data["x"]), WzDataTool.getIntValue(data["y"]));
                    bool flip = WzDataTool.getIntValue(data["f"], 0) > 0;
                    WzImage dataImg = reactorWZ.WzDirectory.GetImageByName(imgName);
                    if (dataImg["info"]["link"] != null) {
                        dataImg = reactorWZ.WzDirectory.GetImageByName(WzDataTool.getStringValue(dataImg["info"]["link"]) + ".img");
                        }
                    WzCanvasProperty canvasData = (WzCanvasProperty)dataImg["0"]["0"];
                    WzVectorProperty canvasOrigin = (WzVectorProperty)canvasData["origin"];
                    Bitmap image = canvasData.PngProperty.PNG;
                    Point origin = new Point(canvasOrigin.X.Value, canvasOrigin.Y.Value);

                    reactorObject.idStr = idStr;
                    reactorObject.id = Int32.Parse(idStr);
                    reactorObject.flip = flip;
                    reactorObject.image = image;
                    reactorObject.origin = origin;
                    reactorObject.pos = pos;
                    reactorObject.map = this;

                    mapReactor.Add(reactorObject);
                    }
                }

            if (img["life"] != null) {
                WzSubProperty dataRoot = (WzSubProperty)img["life"];
                foreach (IWzImageProperty data in dataRoot.WzProperties) {
                    WzLifeObject lifeObject = new WzLifeObject();
                    string type = WzDataTool.getStringValue(data["type"]);
                    if (type == "n") {
                        string idStr = WzDataTool.getStringValue(data["id"]);
                        string imgName = idStr + ".img";
                        Point pos = new Point(WzDataTool.getIntValue(data["x"]), WzDataTool.getIntValue(data["y"]));
                        int fh = WzDataTool.getIntValue(data["fh"]);
                        bool flip = WzDataTool.getIntValue(data["f"], 0) > 0;
                        int cy = WzDataTool.getIntValue(data["cy"]);
                        WzImage dataImg = npcWZ.WzDirectory.GetImageByName(imgName);
                        if (dataImg["info"]["link"] != null) {
                            dataImg = npcWZ.WzDirectory.GetImageByName(WzDataTool.getStringValue(dataImg["info"]["link"]) + ".img");
                            }
                        WzCanvasProperty canvasData = (WzCanvasProperty)dataImg["stand"]["0"];
                        WzVectorProperty canvasOrigin = (WzVectorProperty) canvasData["origin"];
                        Bitmap image = canvasData.PngProperty.PNG;
                        Point origin = new Point(canvasOrigin.X.Value, canvasOrigin.Y.Value);

                        lifeObject.id = Int32.Parse(idStr);
                        lifeObject.flip = flip;
                        lifeObject.image = image;
                        lifeObject.origin = origin;
                        lifeObject.pos = pos;
                        lifeObject.type = type;
                        lifeObject.cY = cy;
                        lifeObject.map = this;

                        mapLife.Add(lifeObject);

                        } else if (type == "m") {
                        string idStr = WzDataTool.getStringValue(data["id"]);
                        string imgName = idStr + ".img";
                        Point pos = new Point(WzDataTool.getIntValue(data["x"]), WzDataTool.getIntValue(data["y"]));
                        int fh = WzDataTool.getIntValue(data["fh"]);
                        bool flip = WzDataTool.getIntValue(data["f"], 0) > 0;
                        int cy = WzDataTool.getIntValue(data["cy"]);
                        WzImage dataImg = mobWZ.WzDirectory.GetImageByName(imgName);
                        if (dataImg["info"]["link"] != null) {
                            dataImg = mobWZ.WzDirectory.GetImageByName(WzDataTool.getStringValue(dataImg["info"]["link"]) + ".img");
                            }
                        WzCanvasProperty canvasData = null;

                        if (dataImg["stand"] != null) {
                            canvasData = (WzCanvasProperty)dataImg["stand"]["0"];
                            } else if (dataImg["fly"] != null) {
                            canvasData = (WzCanvasProperty)dataImg["fly"]["0"];
                            } else {
                            throw new Exception("cannot find valid mob animation");
                            }
                        WzVectorProperty canvasOrigin = (WzVectorProperty)canvasData["origin"];
                        Bitmap image = canvasData.PngProperty.PNG;
                        Point origin = new Point(canvasOrigin.X.Value, canvasOrigin.Y.Value);

                        lifeObject.id = Int32.Parse(idStr);
                        lifeObject.flip = flip;
                        lifeObject.image = image;
                        lifeObject.origin = origin;
                        lifeObject.pos = pos;
                        lifeObject.type = type;
                        lifeObject.cY = cy;
                        lifeObject.map = this;

                        mapLife.Add(lifeObject);

                        } else {
                        throw new Exception("Illegal Life Type");
                        }
                    }
                }




            }

        public void save() {

            for (int i = 0; i < 8; i++) {
                WzSubProperty infoDir = (WzSubProperty)img[i.ToString()]["info"];
                WzSubProperty objDir = (WzSubProperty)img[i.ToString()]["obj"];
                WzSubProperty tileDir = (WzSubProperty)img[i.ToString()]["tile"];
                objDir.ClearProperties();
                for (int j = 0; j < mapLayerObj[i].Count; j++) {
                    WzLayerObject layerObject = mapLayerObj[i][j];
                    WzSubProperty newObject = new WzSubProperty(i.ToString());
                    newObject.AddProperty(new WzCompressedIntProperty("f", layerObject.flip ? 1 : 0));
                    newObject.AddProperty(new WzStringProperty("l0", layerObject.l0));
                    newObject.AddProperty(new WzStringProperty("l1", layerObject.l1));
                    newObject.AddProperty(new WzStringProperty("l2", layerObject.l2));
                    newObject.AddProperty(new WzStringProperty("oS", layerObject.objectSet));
                    newObject.AddProperty(new WzCompressedIntProperty("x", layerObject.pos.X));
                    newObject.AddProperty(new WzCompressedIntProperty("y", layerObject.pos.Y));
                    newObject.AddProperty(new WzCompressedIntProperty("z", layerObject.z));
                    newObject.AddProperty(new WzCompressedIntProperty("zM", layerObject.zM));
                    objDir.AddProperty(newObject);
                    }
                infoDir.ClearProperties();
                tileDir.ClearProperties();
                for (int j = 0; j < mapLayerTile[i].Count; j++) {
                    WzLayerObject layerObject = mapLayerTile[i][j];
                    if (j == 0) {
                        infoDir.AddProperty(new WzStringProperty("tS", layerObject.tileSet));
                        }
                    WzSubProperty newTile = new WzSubProperty(i.ToString());
                    newTile.AddProperty(new WzCompressedIntProperty("no", layerObject.number));
                    newTile.AddProperty(new WzStringProperty("u", layerObject.tileSubset));
                    newTile.AddProperty(new WzCompressedIntProperty("x", layerObject.pos.X));
                    newTile.AddProperty(new WzCompressedIntProperty("y", layerObject.pos.Y));
                    newTile.AddProperty(new WzCompressedIntProperty("zM", layerObject.zM));
                    tileDir.AddProperty(newTile);
                    }
                }

            WzSubProperty reactorDir = (WzSubProperty)img["reactor"];
            reactorDir.ClearProperties();
            for (int i = 0; i < mapReactor.Count; i++) {
                WzReactorObject reactorObject = mapReactor[i];
                WzSubProperty newReactor = new WzSubProperty(i.ToString());
                newReactor.AddProperty(new WzCompressedIntProperty("f", reactorObject.flip ? 1 : 0));
                newReactor.AddProperty(new WzStringProperty("id", reactorObject.idStr));
                newReactor.AddProperty(new WzStringProperty("name", ""));
                newReactor.AddProperty(new WzCompressedIntProperty("x", reactorObject.pos.X));
                newReactor.AddProperty(new WzCompressedIntProperty("y", reactorObject.pos.Y));
                reactorDir.AddProperty(newReactor);
                }

            
            }

        public Bitmap renderMap(int drawMask) {
            this.drawMask = drawMask;
            Bitmap mapCanvas = new Bitmap(w, h);
            Graphics g = Graphics.FromImage(mapCanvas);
            drawMap(g, drawMask);
            return mapCanvas;
            }

        public void drawMap(Graphics g, int drawMask) {
            //g.Clear(Color.Black);
            g.Clear(Color.CornflowerBlue);
            
            drawMapBack(g);
            drawMapLayer(g, drawMask);

            if ((drawMask & (int)WzMapDrawMask.REACTOR) != 0) {
                drawMapReactor(g);
                }
            if ((drawMask & (int)WzMapDrawMask.LIFE) != 0) {
                drawMapLife(g);
                }
            if ((drawMask & (int)WzMapDrawMask.LR) != 0) {
                drawMapLadderRope(g);
                }
            if ((drawMask & (int)WzMapDrawMask.PORT) != 0) {
                drawMapPortal(g);
                }
            if ((drawMask & (int)WzMapDrawMask.FH) != 0) {
                //drawMapFootholdTree(g);
                drawMapFoothold(g);
                }
            }

        public void drawMapBack(Graphics g) {

            }

        public void drawMapLife(Graphics g) {
            foreach (WzLifeObject lifeObject in mapLife) {
                lifeObject.drawObject(g);
                }
            }

        public void drawMapLayer(Graphics g, int drawMask) {
            for (int i = 0; i < 8; i++) {
                if ((drawMask & (int)WzMapDrawMask.OBJ) > 0) {
                    foreach (WzLayerObject layerObject in mapLayerObj[i]) {
                        layerObject.drawObject(g);
                        }
                    }
                if ((drawMask & (int)WzMapDrawMask.TILE) > 0) {
                    foreach (WzLayerObject layerObject in mapLayerTile[i]) {
                        layerObject.drawObject(g);
                        }
                    }
                }
            }

        public void drawMapReactor(Graphics g) {
            foreach (WzReactorObject reactorObject in mapReactor) {
                reactorObject.drawObject(g);
                }
            }

        public void drawMapPortal(Graphics g) {

            }

        public void drawMapLadderRope(Graphics g) {

            }

        public void drawMapFootholdTree(Graphics g) {

            }

        public void drawMapFoothold(Graphics g) {
            foreach (WzFootholdObject footholdObject in mapFoothold) {
                footholdObject.drawObject(g);
                }
            }
        }
    }